/**
 * 
 */
package jvm.jtacck.db;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

import jvm.jtacck.db.records.*;

/**
 * @author Chris Gamble
 * 
 *         A DatabaseHandler is an Interface to be used in the Jtacck Lab
 *         Transport System. It's functionality is to create a barrier between
 *         database access and the rest of the system. The interface allows the
 *         database system to change without changing the rest of the system
 *         along with it.
 * 
 *         Current functionality is open(), close(), and addRecord(r),
 *         isClosed(), login(u),
 */
public interface DatabaseHandler {

    /**
     * Opens a connection to the database if one has is not already open.
     * 
     * @throws SQLException
     *             if a database access error occurs
     */
    public void open() throws SQLException;

    /**
     * Closes the connection to the database if it has not already been closed
     * 
     * @throws SQLException
     *             if a database access error occurs
     */
    public void close() throws SQLException;

    /**
     * Checks to see if the connection is open or closed and returns true if it
     * is closed.
     * 
     * @return True if the database connection is closed.
     * @throws SQLException
     *             if a database access error occurs
     */
    public boolean isClosed() throws SQLException;

    /**
     * Takes a username and password, and if there is a corresponding username
     * with that password, returns the User for that username.
     * 
     * @param username
     *            The username to login into the system with.
     * @param password
     *            The password to login into the system with.
     * @return If there is a user u with matching username and password, then
     *         returns the User of that u. Else returns null. Null means the
     *         attempt to login failed.
     * @throws SQLException
     *             if a database access error occurs
     */
    public User login(String username, String password);

    /**
     * Adds the given Record to the database.
     * 
     * @param r
     *            The Record to add to the database, can be any of these
     *            subclasses of Record: ClientSite, Courier, Hospital,
     *            ShippingInformation, Status, User, UserType. Integer based
     *            ID's are allowed to be null as they will be provided a unique
     *            ID from the database.
     * @throws SQLException
     *             if a database access error occurs
     */
    public void addRecord(ClientSite cs) throws SQLException;
    public void addRecord(Courier c) throws SQLException;
    public void addRecord(Hospital h) throws SQLException;
    public void addRecord(ShippingInformation si) throws SQLException;
    public void addRecord(Specimen sp) throws SQLException;
    public void addRecord(Status st) throws SQLException;
    public void addRecord(User u) throws SQLException;
    public void addRecord(UserType ut) throws SQLException;
    
    /**
     * Changes the Record given in the database to the new values. Any unique
     * identifiers must remain constant.
     * 
     * When updating a Specimen, the Items of Specimen.contents, will add any
     * new item_ids and remove any item_ids that are not found in the new
     * contents.
     * 
     * @param r
     *            The Record to add to the database, can be any of these
     *            subclasses of Record: ClientSite, Courier, Hospital,
     *            ShippingInformation, Specimen, Status, User, UserType. The ID
     *            must not change.
     * @throws SQLException
     *             if a database access error occurs
     */
    public void changeRecord(CheckListPair clp) throws SQLException;
    public void changeRecord(ClientSite cs) throws SQLException;
    public void changeRecord(Courier c) throws SQLException;
    public void changeRecord(Hospital h) throws SQLException;
    public void changeRecord(ShippingInformation si) throws SQLException;
    public void changeRecord(Specimen sp) throws SQLException;
    public void changeRecord(Status st) throws SQLException;
    public void changeRecord(User u) throws SQLException;
    public void changeRecord(UserType ut) throws SQLException;
    
    /**
     * Removes the Record given from the database.
     * 
     * An SQLException will be thrown if a Record that is currently in use by a
     * ShippingInformation and will result in the Record not being removed from
     * the database
     * 
     * @param r
     *            The Record to remove to the database, can be any of these
     *            subclasses of Record: ClientSite, Courier, Hospital,
     *            ShippingInformation, Specimen, Status, User, UserType. The ID
     *            must not change.
     * @throws SQLException
     *             if a database access error occurs
     */
    public void removeRecord(ClientSite cs) throws SQLException;
    public void removeRecord(Courier c) throws SQLException;
    public void removeRecord(Hospital h) throws SQLException;
    public void removeRecord(ShippingInformation si) throws SQLException;
    public void removeRecord(Status st) throws SQLException;
    public void removeRecord(User u) throws SQLException;
    public void removeRecord(UserType ut) throws SQLException;

    /**
     * Returns a single ClientSite for the id given
     * 
     * @param client_id
     *            the id for the specific ClientSite request
     * @return either a ClientSite or null if the site is not found.
     * @throws SQLException
     *             if a database access error occurs
     */
    public ClientSite getClientSiteByID(int client_id) throws SQLException;

    /**
     * Takes a username and returns the Courier of that username if the User is
     * a Courier.
     * 
     * @param username
     *            The unique username of a User who's UserType is a Courier
     * @return The Courier Record associated with the given username.
     * @throws SQLException
     *             if a database access error occurs
     */
    public Courier getCourierByID(String username) throws SQLException;

    /**
     * Returns a single User for the id given
     * 
     * @param hospital_id
     *            the id for the specific User request
     * @return either a Hospital or null if the hospital is not found.
     */
    public Hospital getHospitalByID(int hospital_id) throws SQLException;

    /**
     * Takes an int and returns the Item corresponding to that id.
     * 
     * @param item_id
     *            The id of the Item requested
     * @return either the Item or null if the item is not found.
     * @throws SQLException
     *             if a database access error occurs
     */
    public Item getItemByID(int item_id) throws SQLException;

    /**
     * Takes a barcode and returns the ShippingInformation corresponding to that
     * barcode
     * 
     * @param barcode
     *            The barcode of the Specimen whose ShippingInformation is
     *            requested
     * @return either the ShippingInformation or null if the ShippingInformation
     *         is not found.
     * @throws SQLException
     *             if a database access error occurs
     */
    public ShippingInformation getShippingByID(String barcode) throws SQLException;

    /**
     * Takes a barcode and returns the ShippingInformation corresponding to that
     * barcode
     * 
     * @param barcode
     *            The barcode of the Specimen requested
     * @return either the Specimen or null if the specimen is not found.
     * @throws SQLException
     *             if a database access error occurs
     */
    public Specimen getSpecimenByID(String barcode) throws SQLException;

    /**
     * Takes an int and returns the Status corresponding to that id.
     * 
     * @param status_id
     *            The id of the Status requested
     * @return either the Status or null if the Status is not found.
     * @throws SQLException
     *             if a database access error occurs
     */
    public Status getStatusByID(int status_id) throws SQLException;

    /**
     * Returns a single User for the id given
     * 
     * @param username
     *            the username for the specific User request
     * @return either a User or null if the User is not found.
     */
    public User getUserByID(String username) throws SQLException;

    /**
     * Takes an int and returns the UserType corresponding to that id.
     * 
     * @param type_id
     *            The id of the UserType requested
     * @return either the UserType or null if the UserType is not found.
     * @throws SQLException
     *             if a database access error occurs
     */
    public UserType getUserTypeByID(int type_id) throws SQLException;

    /**
     * Takes the client site and returns a list of all users who are associated
     * with the given site
     * 
     * @param cs
     *            The ClientSite that the requested Users are associated with.
     * @return A List of Users that are associated with cs.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<User> getUsersOf(ClientSite cs) throws SQLException;

    /**
     * Takes a username, and returns the UserType of that username.
     * 
     * @param username
     *            A username of a User in the database
     * @return The UserType of the username given
     * @throws SQLException
     *             if a database access error occurs
     */
    public UserType getUserType(String username) throws SQLException;

    /**
     * Takes a barcode, and returns the ShippingInformation for the Specimen
     * that barcode is an identifier for.
     * 
     * @param barcode
     *            The unique barcode of a Specimen in the database
     * @return The ShippingInformation with the unique identifier of the
     *         Specimen with barcode as their barcode.
     * @throws SQLException
     *             if a database access error occurs
     */
    public ShippingInformation getShippingInfoFor(String barcode)
            throws SQLException;

    /**
     * Returns the checklist pair that is stored in the database. This
     * corresponds to the starting and ending checklists for couriers to use.
     */
    public CheckListPair getCheckLists() throws SQLException;

    /**
     * Takes a ClientSite and returns a list of ShippingInformation for all
     * Specimens that have been shipped from the given ClientSite.
     * 
     * @param clientID
     *            The ClientSite that the requested Specimens were shipped from.
     * @return A List of each ShippingInformation where the Specimens were
     *         shipped from cs.
     * @throws SQLException
     *             if a database access error occurs
     */
    // TODO: overload this method for Users and Hospitals
    public List<ShippingInformation> specimensFrom(ClientSite cs)
            throws SQLException;

    /**
     * Takes a ClientSite and returns a list of ShippingInformation for all
     * Specimens that have destinations of the given ClientSite.
     * 
     * @param clientID
     *            The ClientSite that the requested Specimens were shipped to.
     * @return A List of each ShippingInformation where the Specimens were
     *         shipped to cs.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<ShippingInformation> specimensTo(ClientSite cs)
            throws SQLException;

    /**
     * Returns a list of all ClientSites available.
     * 
     * @return A List containing every ClientSite in the system.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<ClientSite> getAllClientSites() throws SQLException;

    /**
     * Returns a list of all Couriers available.
     * 
     * @return A List containing every Couriers in the system.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<Courier> getAllCouriers() throws SQLException;

    /**
     * Returns a list of all Hospitals available.
     * 
     * @return A List containing every Hospital in the system.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<Hospital> getAllHospitals() throws SQLException;

    /**
     * Returns a list of all Items available. This method is pretty much useless
     * because you should not be messing with items alone, so DON'T USE IT!
     * 
     * @return A List containing every Item in the system.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<Item> getAllItems() throws SQLException;

    /**
     * Returns a list of all ShippingInformation available. This is equivalent
     * to getting it for all Specimens as the barcodes are the same.
     * 
     * @return A List containing every ShippingInformation in the system.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<ShippingInformation> getAllShippingInformation()
            throws SQLException;

    /**
     * Returns a list of all ShippingInformation that doesn't have the status
     * "Arrived". This will be a more brief list and will be the most recent of
     * the specimens
     * 
     * @return A List containing every non delivered specimen in the system.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<ShippingInformation> getNotArrived() throws SQLException;

    /**
     * Returns a list of all Specimens available.
     * 
     * @return A List containing every Specimen in the system.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<Specimen> getAllSpecimens() throws SQLException;

    /**
     * Returns a list of all Statuses available.
     * 
     * @return A List containing every Status in the system.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<Status> getAllStatuses() throws SQLException;

    /**
     * Returns a list of all Users available.
     * 
     * @return A List containing every User in the system.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<User> getAllUsers() throws SQLException;

    /**
     * Returns a list of all UserTypes available.
     * 
     * @return A List containing every UserType in the system.
     * @throws SQLException
     *             if a database access error occurs
     */
    public List<UserType> getAllUserTypes() throws SQLException;
    
    /**
     * Returns a Date object of the last time the ShippingInformation with the 
     * given barcode was update.
     * @param barcode
     *        The id of the ShippingInformation to get the timestamp of
     * @return A Date object with the day and time of the last update to the 
     *         ShippingInformation.
     * @throws SQLException
     *          If a database access error occurs
     */
    public Date getLastUpdate(String barcode) throws SQLException;
    
    /**
     * Returns a Date object of the first time the ShippingInformation with the 
     * given barcode was update.
     * @param barcode
     *        The id of the ShippingInformation to get the timestamp of
     * @return A Date object with the day and time of the first update to the 
     *         ShippingInformation.
     * @throws SQLException
     *          If a database access error occurs
     */
    public Date getFirstUpdate(String barcode) throws SQLException;
    
}
